﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Forms;

using Rsdn.Janus.Framework;
using Rsdn.SmartApp;

namespace Rsdn.Janus
{
    /// <summary>
    /// Контрол для просмотра сообщения.
    /// </summary>
	internal sealed partial class MsgViewer : UserControl
    {
        private IMsg _msg;
        private readonly ServiceManager _serviceManager;
        private readonly StripMenuGenerator _toolbarGenerator;
        private bool _blockExternalNavigation;

        public event EventHandler MsgChanged;

        #region Constructor(s) & Dispose

        public MsgViewer(IServiceProvider provider)
        {
            _serviceManager = new ServiceManager(provider);

            _serviceManager.Publish<IActiveMessagesService>(new MessageViewerActiveMessageService(this));

            this.AssignServices(_serviceManager);

            InitializeComponent();

            _messageBrowser.Navigating += MessageBrowserNavigating;
            _messageBrowser.StatusTextChanged += MessageBrowserStatusTextChanged;

            _toolbarGenerator = new StripMenuGenerator(_serviceManager, _toolStrip, "MessageViewer.Toolbar", true); //MLHIDE
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _toolbarGenerator.Dispose();
                _messageBrowser.Navigating -= MessageBrowserNavigating;
                _messageBrowser.StatusTextChanged -= MessageBrowserStatusTextChanged;
            }

            base.Dispose(disposing);
        }

        #endregion

        #region Private methods

        private static string FormatURI(
            JanusProtocolResourceType resourceType, string parameters)
        {
            return JanusProtocolDispatcher.FormatURI(resourceType, parameters);
        }

        //private static string NationalUrlDecode(string url)
        //{
        //    var encoding = url.IndexOf("%D0") != -1
        //        ? Encoding.UTF8
        //        : Encoding.GetEncoding("windows-1251");

        //    return HttpUtility.UrlDecode(url, encoding);
        //}

        #endregion

        #region Public members

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IMsg Msg
        {
            get
            {
                return _msg;
            }

            set
            {
#if MNU_TRACE
                Trace.WriteLine(string.Format("MNU:Message set - {0}", value)); //MLHIDE
#endif
                if (_msg == value)
                {
#if MNU_TRACE
                    Trace.WriteLine(string.Format("MNU:return"));     //MLHIDE
#endif
                    return;
                }

                _msg = value;
                string url = _msg == null
                                 ? "about:blank"                      //MLHIDE
                                 : FormatURI(JanusProtocolResourceType.Message, _msg.ID.ToString());

                NavigateToUrl(url);

                InvokeMsgChanged();
            }
        }

        public void NavigateToUrl(string url)
        {
            _blockExternalNavigation = true;
            _messageBrowser.Navigate(url);
        }

        /// <summary>
        /// Прокручивает страницу с сообщением на лист вниз.
        /// </summary>
        /// <returns>True - если перелистнули страницу, иначе - false.</returns>
        public bool PageDown()
        {
            if (_messageBrowser.Document != null)
            {
                var msgBody = _messageBrowser.Document.GetElementById("MsgBody"); //MLHIDE

                if (msgBody == null)
                {
                    return false;
                }

                var scrollTop = msgBody.ScrollTop;
                var height = msgBody.ClientRectangle.Height;
                var size = Config.Instance.SmartJumpPageSize;

                msgBody.ScrollTop += (int)((height / 100.0d) * size);

                // если позиция скроллбара не изменилась, 
                // значит достигнут конец.
                return scrollTop != msgBody.ScrollTop;
            }
            return false;
        }

        #endregion

        /// <summary>
        /// Updates the state of the MSG over <see cref="MsgChanged"/> event
        /// </summary>
        public void UpdateMsgState()
        {
            InvokeMsgChanged();
        }

        /// <summary>
        /// Invokes the event MSG changed.
        /// </summary>
        private void InvokeMsgChanged()
        {
            if (MsgChanged != null)
            {
                MsgChanged(this, EventArgs.Empty);
            }
        }

        #region Controls events

        private void MessageBrowserNavigating(object sender, WebBrowserNavigatingEventArgs e)
        {
            if (!_blockExternalNavigation)
            {
                JanusProtocolInfo protocolInfo = JanusProtocolInfo.Parse(e.Url.ToString());
                LinkType linkType = protocolInfo == null ? LinkType.External : protocolInfo.LinkType;
                IOutboxManager obManager = _serviceManager.GetRequiredService<IOutboxManager>();
                ApplicationManager manager = ApplicationManager.Instance;

                switch (linkType)
                {
                    case LinkType.Local:
                        Debug.Assert(protocolInfo != null);
                        if (protocolInfo.ResourceType == JanusProtocolResourceType.Message)
                        {
                            manager.ForumNavigator.SelectMessage(protocolInfo.Id);
                        }
                        else
                        {
                            manager.ForumNavigator.SelectMessage(protocolInfo.Parameters);
                        }
                        break;

                    case LinkType.Absent:
                        Debug.Assert(protocolInfo != null);
                        obManager.AddTopicForDownloadWithConfirm(protocolInfo.Id);
                        e.Cancel = true;
                        break;

                    case LinkType.External:
                        _serviceManager.OpenUrlInBrowser(e.Url.OriginalString);
                        e.Cancel = true;
                        break;
                }
            }
            _blockExternalNavigation = false;
        }

        private void MessageBrowserStatusTextChanged(object sender, EventArgs e)
        {
            //Зачем так усложнять?
            //if (_messageBrowser.Url != null && _messageBrowser.Url.OriginalString == "about:blank")
            //    ClearStatusLabel();
            //else
            //    _statusLabel.Text = NationalUrlDecode(_messageBrowser.StatusText);
            _statusLabel.Text = _messageBrowser.StatusText;
        }

        #endregion
    }
}
